home *** CD-ROM | disk | FTP | other *** search
- (* :Title: Digital Signal Processing Analysis *)
-
- (* :Authors: Brian Evans, James McClellan *)
-
- (*
- :Summary: Perform basic analysis on a one-dimensional discrete-time
- function, including plotting f[n] and graphing the poles
- and zeroes of F[z].
- *)
-
- (* :Context: SignalProcessing`Digital`DSPAnalyze` *)
-
- (* :PackageVersion: 2.7 *)
-
- (*
- :Copyright: Copyright 1989-1991 by Brian L. Evans
- Georgia Tech Research Corporation
-
- Permission to use, copy, modify, and distribute this software
- and its documentation for any purpose and without fee is
- hereby granted, provided that the above copyright notice
- appear in all copies and that both that copyright notice and
- this permission notice appear in supporting documentation,
- and that the name of the Georgia Tech Research Corporation,
- Georgia Tech, or Georgia Institute of Technology not be used
- in advertising or publicity pertaining to distribution of the
- software without specific, written prior permission. Georgia
- Tech makes no representations about the suitability of this
- software for any purpose. It is provided "as is" without
- express or implied warranty.
- *)
-
- (* :History: *)
-
- (* :Keywords: analysis, transforms, signals and systems *)
-
- (* :Source: *)
-
- (* :Warning: *)
-
- (* :Mathematica Version: 1.2 or 2.0 *)
-
- (* :Limitation: *)
-
- (* :Discussion: *)
-
- (* :Functions: DSPAnalyze *)
-
-
-
- (* B E G I N P A C K A G E *)
-
- BeginPackage[ "SignalProcessing`Digital`DSPAnalyze`",
- "SignalProcessing`Digital`DTFT`",
- "SignalProcessing`Digital`DSupport`",
- "SignalProcessing`Digital`ZTransform`",
- "SignalProcessing`Digital`ZSupport`",
- "SignalProcessing`Support`TransSupport`",
- "SignalProcessing`Support`ROC`",
- "SignalProcessing`Support`SigProc`",
- "SignalProcessing`Support`SupCode`" ]
-
-
- If [ TrueQ[ $VersionNumber >= 2.0 ],
- Off[ General::spell ];
- Off[ General::spell1 ] ];
-
-
- (* U S A G E I N F O R M A T I O N *)
-
- DSPAnalyze::usage =
- "DSPAnalyze[f, n] and DSPAnalyze[f, n, start, end] \
- will plot the real values of f[n] from n = Floor[start] to \
- n = Ceiling[end], print its z-transform, indicate conditions \
- for stability, display the pole-zero diagram, and plot the magnitude \
- and phase responses. \
- DSPAnalyze[f, {n1,n2}] and DSPAnalyze[f, {n1,n2}, {s1,s2}, {e1,e2}] \
- treat f as a function of two-variables n1 and n2. \
- The domain of the time-domain graph is n1 from s1 to e1 and \
- n2 from s2 to e2. \
- All non-variable symbols will be assigned a value of 1 when the \
- analyzer generates graphics (override this with options like a -> 2)."
-
- (* E N D U S A G E I N F O R M A T I O N *)
-
-
- Begin["`Private`"]
-
-
- (* M E S S A G E S *)
-
- ZTransform::notvalid = "The forward z-transform could not be found."
- DSPAnalyze::hasval =
- "The variable '' has value so it could not be used as a \
- transform variable; '' was used instead."
- DTFTransform::notvalid = "The forward DTFT could not be found."
-
-
- (* S U P P O R T I N G F U N C T I O N S *)
-
- (* dspAnalyzeQ *)
- dspAnalyzeQ[start_, end_] :=
- NumberQ[N[start]] && NumberQ[N[end]] && N[end >= start]
-
- (* checkvar *)
- SetAttributes[checkvar, {HoldFirst}]
- checkvar[ xsym_, xval_, str_ ] := xsym /; SameQ[xsym, xval]
- checkvar[ xsym_, xval_, str_ ] :=
- Block [ {sym},
- sym = Unique["z"];
- Message[ DSPAnalyze::hasval, str, sym ];
- sym ]
-
- (* formatting-- this works if and only if the variables do not appear *)
- (* in a Block statement; i.e., they must be global to the package *)
- w/: Format[ w ] := "w"
- w1/: Format[ w1 ] := "w1"
- w2/: Format[ w2 ] := "w2"
-
- z/: Format[ z ] := "z"
- z1/: Format[ z1 ] := "z1"
- z2/: Format[ z2 ] := "z2"
-
- (* printDefaults *)
- printDefaults[oplist_, varlist_, defaultvalues_] :=
- Block [ {},
- If [ EmptyQ[oplist],
- Print[ "For plotting only, these symbols will" ];
- Print[ "be assigned a value of 1: ", varlist ],
- Print[ "For plotting only, these symbols will" ];
- Print[ "will be assigned default values:" ];
- Print[ defaultvalues ] ] ]
-
- (* printStability *)
- printStability[ztrans_] :=
- Block [ {stable},
- stable = Stable[ztrans];
- Which [ SameQ[stable, True],
- Print[ "The system is stable." ],
- SameQ[stable, False],
- Print[ "The system is not stable." ],
- True,
- Print[ "The system is stable if ", stable ] ];
- stable ]
-
- (* zToFreqResp *)
- zToFreqResp[ funct_, ztrans_, defaultvalues_, onedflag_, zrules_ ] :=
- Block [ {mag, plotrange, rm, rp, stable, zfreqresp},
-
- (* Print the sequence and its z-transform *)
- Print[ funct ];
- Print[ "has the following z-transform:" ];
- Print[ TheFunction[ztrans] ];
-
- (* Print the Region of Convergence *)
- Print[ "The region of convergence is:" ];
- rm = GetRMinus[ztrans];
- rp = GetRPlus[ztrans];
- If [ onedflag,
- Print[ rm, " < |z| < ", rp ],
- Print[ rm[[1]], " < |z1| < ", rp[[1]] ];
- Print[ rm[[2]], " < |z2| < ", rp[[2]] ] ];
-
- (* Print stability information *)
- stable = printStability[ztrans];
-
- (* From now on, the default values are used *)
- If [ ! EmptyQ[defaultvalues],
- Print[ "The default values are now being considered." ] ];
-
- (* Show the Pole-Zero Plot *)
- PoleZeroPlot[ztrans /. defaultvalues];
-
- If [ stable /. defaultvalues,
- Print[ "Since the sequence is stable, the" ];
- Print[ "frequency response can be computed" ];
- Print[ "directly from the z-transform:" ];
- zfreqresp = TheFunction[ztrans] /. zrules;
- Print[ zfreqresp ];
- plotrange = All;
- mag = Log,
-
- Print[ "Since the sequence is not stable, the" ];
- Print[ "frequency response has no meaning, but" ];
- Print[ "it will be plotted anyway. However, the DC" ];
- Print[ "(zero frequency) term will be Infinity which" ];
- Print[ "will generate a warning from Mathematica." ];
- plotrange = Automatic;
- mag = Linear,
-
- Print[ "Even though the stability of the sequence" ];
- Print[ "is not known, the frequency response will" ];
- Print[ "still be plotted." ];
- plotrange = Automatic;
- mag = Linear ];
-
- { mag, plotrange, zfreqresp } ]
-
-
- (* D S P A n a l y z e *)
-
- DSPAnalyze[f_, n_Symbol] := DSPAnalyze[f, n, 0]
- DSPAnalyze[f_, n_Symbol, start_] := DSPAnalyze[f, n, start, start + 40]
-
- DSPAnalyze[f_, n_Symbol, start_, end_, op___] :=
- Block [ {bogus, defaultvalues = {}, dtft, freqresp, fnumeric,
- ftemp, funct, mag, oplist, plotrange = All, varlist,
- zfreqresp, ztrans},
-
- oplist = ToList[op];
- funct = ToDiscrete[f];
-
- (* DISCRETE-TIME ANALYSIS *)
-
- (* Convert expression to plottable/functional form *)
- (* and replace constants like Pi with numerical value *)
-
- fnumeric = N[ TheFunction[ funct ] ];
-
- (* Find all valueless symbols besides the time variable *)
- (* The first parameter in Summation is a local symbol *)
-
- ftemp = fnumeric /.
- ( Summation[m_, l_, u_, inc_][expr_] :>
- bogus[l, u, inc, GetVariables[expr /. m -> l]] );
- varlist = Select[GetVariables[ftemp /. oplist],
- Function[var, ! SameQ[var, n]]];
- If [ (! EmptyQ[varlist]) || (! EmptyQ[oplist]),
- defaultvalues = oplist ~Join~ Map[(#1 -> 1)&, varlist];
- printDefaults[oplist, varlist, defaultvalues];
- fnumeric = fnumeric /. defaultvalues ];
-
- (* Plot "time"-domain *)
-
- SequencePlot[ fnumeric, {n, start, end},
- PlotLabel -> "Discrete-Time Domain Analysis" ];
-
- (* Z-DOMAIN ANALYSIS *)
-
- (* Find F[z]; if it exists, print it out, give stability *)
- (* information, and display a pole-zero plot. *)
-
- ztrans = ZTransform[funct, n, z];
- If [ ! SameQ[Head[ztrans], ZTransData],
- Message[ZTransform::notvalid];
- mag = Linear,
- { mag, plotrange, zfreqresp } =
- zToFreqResp[ funct, ztrans, defaultvalues,
- True, (z -> Exp[I w]) ] ];
-
- (* FREQUENCY-DOMAIN ANALYSIS *)
-
- (* Determine the frequency response *)
-
- dtft = DTFTransform[funct, n, w, Simplify -> True];
- If [ ! SameQ[Head[dtft], DTFTData],
- Message[DTFTransform::notvalid]; Return[ztrans] ];
- freqresp = TheFunction[dtft];
-
- (* Plot the interesting section of the freq. response *)
-
- If [ ! SameQ[freqresp, zfreqresp],
- Print[ funct ];
- Print[ "has the following frequency response:"];
- Print[ freqresp ];
- Print[ "where the frequency response is periodic" ];
- Print[ "usually with period 2 Pi" ] ];
-
- freqresp = ToContinuous[freqresp];
- MagPhasePlot[ freqresp /. defaultvalues,
- {w, -2 Pi, 2 Pi},
- Domain -> Continuous, DomainScale -> Linear,
- MagRangeScale -> mag, PhaseRangeScale -> Degree,
- PlotRange -> plotrange ];
-
- (* Return the z-transform *)
-
- ztrans /. ( z -> checkvar[Global`z, Global`z, "z"] ) ] /;
- N [ dspAnalyzeQ[start, end] ]
-
-
- DSPAnalyze[f_, {n1_Symbol, n2_Symbol}] := DSPAnalyze[f, {n1, n2}, {0, 0}]
- DSPAnalyze[f_, {n1_Symbol, n2_Symbol}, start_] :=
- DSPAnalyze[f, {n1, n2}, start, start + {9, 9}]
-
- DSPAnalyze[f_, {n1_Symbol, n2_Symbol}, start_, end_, op___] :=
- Block [ {coordlist, defaultvalues = {}, dtft, freqresp, ftemp, funct,
- mag, nlist, oplist, plotrange = All, stable, varlist,
- wlist, zfreqresp, zlist, ztrans},
-
- oplist = ToList[op];
-
- nlist = { n1, n2 };
- wlist = { w1, w2 };
- zlist = { z1, z2 };
- funct = ToDiscrete[f];
-
- (* DISCRETE-TIME ANALYSIS *)
-
- (* Convert expression to plottable/functional form *)
- (* and replace constants like Pi with numerical value *)
-
- fnumeric = N[ TheFunction[ funct ] ];
-
- (* Find all valueless symbols besides the time variable *)
- (* The first parameter in Summation is a local symbol *)
-
- ftemp = fnumeric /.
- ( Summation[m_, l_, u_, inc_][expr_] :>
- bogus[l, u, inc, GetVariables[expr /. m -> l]] );
- varlist = Select[GetVariables[ftemp /. oplist],
- Function[var,
- ! SameQ[var,n1] && ! SameQ[var,n2]]];
- If [ (! EmptyQ[varlist]) || (! EmptyQ[oplist]),
- defaultvalues = oplist ~Join~ Map[(#1 -> 1)&, varlist];
- printDefaults[oplist, varlist, defaultvalues];
- fnumeric = fnumeric /. defaultvalues ];
-
- (* Generate three-dimensional coordinates for plot *)
-
- SequencePlot[ fnumeric,
- { n1, start[[1]], end[[1]] },
- { n2, start[[2]], end[[2]] },
- PlotLabel -> "Discrete-Time Domain Analysis" ];
-
- (* Z-DOMAIN ANALYSIS *)
-
- (* Find F[z] and print it out. *)
-
- ztrans = ZTransform[funct, nlist, zlist];
- If [ ! SameQ[Head[ztrans], ZTransData],
- Message[ZTransform::notvalid];
- mag = Linear,
-
- { mag, plotrange, zfreqresp } =
- zToFreqResp[ funct, ztrans, defaultvalues, False,
- ReplaceWith[zlist, {Exp[I w1], Exp[I w2]}] ] ];
-
- (* FREQUENCY-DOMAIN ANALYSIS *)
-
- (* Determine the frequency response *)
-
- dtft = DTFTransform[funct, nlist, wlist];
- If [ ! SameQ[Head[dtft], DTFTData],
- Message[DTFT::notvalid]; Return[ztrans] ];
- freqresp = TheFunction[dtft];
-
- (* Plot the interesting section of the freq. response *)
-
- If [ ! SameQ[freqresp, zfreqresp],
- Print[ funct ];
- Print[ "has the following frequency response:" ];
- Print[ freqresp ] ];
-
- (* Making the freqresp periodic takes too long to plot: *)
- (* Periodic[{2 Pi, 2 Pi}, {w1, w2}][freqresp] *)
-
- MagPhasePlot[ freqresp /. defaultvalues,
- {w1, 0, 2 Pi}, {w2, 0, 2 Pi},
- Domain -> Continuous, DomainScale -> Linear,
- MagRangeScale -> mag, PhaseRangeScale -> Degree,
- PlotRange -> plotrange ];
-
- (* Return the z-transform *)
-
- ztrans /. { z1 -> checkvar[Global`z1, Global`z1, "z1"],
- z2 -> checkvar[Global`z2, Global`z2, "z2"] } ] /;
-
- N [ dspAnalyzeQ[ start[[1]], end[[1]] ] &&
- dspAnalyzeQ[ start[[2]], end[[2]] ] ]
-
-
- (* E N D P A C K A G E *)
-
- End[]
- EndPackage[]
-
- If [ TrueQ[ $VersionNumber >= 2.0 ],
- On[ General::spell ];
- On[ General::spell1 ] ];
-
-
- (* H E L P I N F O R M A T I O N *)
-
- Combine[ SPfunctions, { DSPAnalyze } ]
- Protect[ DSPAnalyze ]
-
-
- (* E N D I N G M E S S A G E *)
-
- Print["The digital signal analyzer is now loaded."]
- Null
-